package com.android.bonn.fast.adapter;

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * author huangyunlin@snqu.com
 * date 2018/10/16
 * description
 */
public class SimpleCellDelegateAdapter extends RecyclerView.Adapter<CellViewHolder> {

    private AsyncListDiffer<Object> mAsyncListDiffer = null;

    private List<Object> dataList = new ArrayList<>();

    private final PrefetchViewPool prefetchViewPool = new PrefetchViewPool();

    public List getSubmitList() {
        if (mAsyncListDiffer != null) {
            return mAsyncListDiffer.getCurrentList();
        }
        return dataList;
    }

    public <T> T getItem(int position) {

        if (mAsyncListDiffer == null) {
            return (T) dataList.get(position);
        }

        return (T) mAsyncListDiffer.getCurrentList().get(position);
    }

    private SimpleCellDelegateAdapter(Builder builder) {
        init(builder);
        if (builder.itemCallback != null) {
            mAsyncListDiffer = new AsyncListDiffer<>(this, builder.itemCallback);
        }
    }

    private ArrayMap<Integer, CellTypes> mCellTypes;

    private void init(Builder builder) {
        mCellTypes = builder.cellTypes;
        int size = mCellTypes.size();
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < size; i++) {
            int layoutId = mCellTypes.keyAt(i);
            map.put(layoutId, i);
        }
        prefetchViewPool.setPrefetchedViewTypeList(map);

    }

    @NonNull
    @Override
    public CellViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return normalItemView(parent, viewType);
    }

    private CellViewHolder normalItemView(@NonNull ViewGroup viewGroup, int viewType) {
        CellTypes cellTypes = mCellTypes.get(viewType);
        CellViewCreator cellViewCreator = cellTypes.getCellViewCreator();
        int itemViewId = cellViewCreator.getItemViewId();
        View itemView = prefetchViewPool.getPrefetchedItemBinding(viewGroup, itemViewId);
        CellView cellView = cellViewCreator.create(itemView);
        cellView.setAdapter(this);
        cellView.setOnItemViewClickListener(cellTypes.getListener());
        return cellView;
    }

    @Override
    public int getItemViewType(int position) {
        Object item = getItem(position);
        for (int i = 0; i < mCellTypes.values().size(); i++) {
            CellTypes cellType = mCellTypes.valueAt(i);
            boolean ofView = cellType.typeOfView(position, item);
            if (ofView) {
                return cellType.getModelType();
            }
        }
        return position;
    }

    @Override
    public void onBindViewHolder(@NonNull CellViewHolder holder, int position) {
        Object item = getInternalItem(position);
        holder.onBind(item, position);
    }

    private Object getInternalItem(int position) {

        if (mAsyncListDiffer == null) {
            return dataList.get(position);
        }

        return mAsyncListDiffer.getCurrentList().get(position);
    }

    @Override
    public void onBindViewHolder(@NonNull CellViewHolder holder, int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {
            onBindViewHolder(holder, position);
        } else {
            Object item = getItem(position);
            holder.onBind(item, position, payloads);
        }
    }

    @Override
    public void onViewRecycled(@NonNull CellViewHolder holder) {
        super.onViewRecycled(holder);
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull final RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        prefetchViewPool.detachedFromRecyclerView();
    }

    public void clear() {
        if (mAsyncListDiffer == null) {
            dataList.clear();
            notifyDataSetChanged();
        } else {
            mAsyncListDiffer.submitList(new ArrayList<>());
        }
    }

    public void submitList(@Nullable List list) {
        if (mAsyncListDiffer == null) {
            dataList.addAll(list);
        } else {
            mAsyncListDiffer.submitList(list);
        }
    }

    public void setDataList(@Nullable List list) {
        dataList = list;
    }

    @Override
    public int getItemCount() {

        if (mAsyncListDiffer == null) {
            return dataList.size();
        }

        return mAsyncListDiffer.getCurrentList().size();
    }

    public static class Builder {
        private ArrayMap<Integer, CellTypes> cellTypes;

        public Builder() {
            cellTypes = new ArrayMap<>();
        }

        public <MODEL, VIEW extends CellView<MODEL>> Builder putItem(CellViewCreator<MODEL, VIEW> providerClass) {
            cellTypes.put(providerClass.getItemViewId(), new CellTypes<>(providerClass.getItemViewId(), providerClass));
            return this;
        }

        public <MODEL, VIEW extends CellView<MODEL>> Builder putItem(CellViewCreator<MODEL, VIEW> providerClass, OnItemViewClickListener<MODEL> listener) {
            cellTypes.put(providerClass.getItemViewId(), new CellTypes<>(providerClass.getItemViewId(), providerClass, listener));
            return this;
        }

        private DiffUtil.ItemCallback<Object> itemCallback;

        public Builder setDiffItemCallback(DiffUtil.ItemCallback<Object> itemCallback) {
            this.itemCallback = itemCallback;
            return this;
        }

        public SimpleCellDelegateAdapter build() {
            return new SimpleCellDelegateAdapter(this);
        }
    }

}